/*****************************************************
** Author:
** Date: 2019-07-25
*
*****************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
#include <bcm2835.h>
#include "i2c_if.h"
#include "pcf8575.h"

#define log_dbg(_fmt_, ...)   \
            printf("[APP][%s:%d][%s][DBG] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define log_inf(_fmt_, ...)   \
            printf("[APP][%s:%d][%s][INF] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define log_wrn(_fmt_, ...)   \
            printf("[APP][%s:%d][%s][WRN] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define log_err(_fmt_, ...)   \
            printf("[APP][%s:%d][%s][ERR] "_fmt_"\r\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)

#define PCF8575_I2C_ADDR 0x20
#define PCF8575_I2C_RATE 100000

#define PCF8575_BCM2835_PIN_INT 4

#define APP_BEEP_GPIO   0
#define APP_TOUCH_GPIO  1

/**
 * @brief
 * @param  None
 * @retval None
 */
static void pcf8575_gpio_init(void)
{
    bcm2835_gpio_fsel(PCF8575_BCM2835_PIN_INT, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_set_pud(PCF8575_BCM2835_PIN_INT, BCM2835_GPIO_PUD_UP);
}

static unsigned char pcf8575_int_level(void)
{
    return bcm2835_gpio_lev(PCF8575_BCM2835_PIN_INT);
}

static void plat_delay_ms(unsigned int ms)
{
    bcm2835_delay(ms);
}

static void plat_delay_us(unsigned int us)
{
    bcm2835_delayMicroseconds(us);
}

static void app_hexdump(char *str, unsigned char *data, unsigned int len)
{
    printf("hexdump %p len %d %s", data, len, str);
    for (int i = 0; i < len; i++) {
        if (!(i & 0xf))
            printf("\n%p:", &data[i]);
        printf(" %02x", data[i]);
    }
    printf("\n");
}

static int pcf8575_dev_init(pcf8575_obj_t *obj)
{
    pcf8575_gpio_init();

    i2c_init(PCF8575_I2C_ADDR, PCF8575_I2C_RATE, BCM2835_I2C_CLOCK_DIVIDER_2500);

    obj->read = i2c_read;
    obj->write = i2c_write;
    // obj->delay_ms = plat_delay_ms;
    // obj->delay_us = plat_delay_us;

    log_inf("pcf8575 dev init done");
    return 0;
}

static void exit_handler(int signo)
{
    //System Exit
    log_inf("Program Stop");

    i2c_deinit();
    bcm2835_close();

    exit(0);
}

int main(int argc, char const *argv[])
{
    static pcf8575_obj_t pcf8575;
    struct timeval tv1, tv2;
    unsigned short io;
    int ret, cnt, beep;

    if (!bcm2835_init()) {
        log_err("bcm2835_init failed. Are you running as root??\n");
        return -1;
    }

    if (pcf8575_dev_init(&pcf8575) < 0) {
        log_err("pcf8575 init failed");
        return -1;
    }

    // Exception handling:ctrl + c
    signal(SIGINT, exit_handler);

    log_inf("init done");

    // cnt = 10 * 10;
    cnt = 0;
    beep = 0;
    while (1) {

        gettimeofday(&tv1, NULL);

        io = 0;
        if ((ret = pcf8575_read_io(&pcf8575, &io)) != 0) {
            log_wrn("read io failed %d", ret);
            goto err;
        }

        gettimeofday(&tv2, NULL);

        log_dbg("read io %#x delat time %ldus", io,
            (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec);

        if ((cnt++ % 0x08) == 0) {
            beep = !beep;
            io |= (1 << APP_TOUCH_GPIO);
            ret = pcf8575_write_io(&pcf8575, beep ? io | (1 << APP_BEEP_GPIO) : io & ~(1 << APP_BEEP_GPIO));
            if (ret != 0) {
                log_wrn("write io failed %d", ret);
                goto err;
            }
        }

        io = 0;
        if ((ret = pcf8575_read_io(&pcf8575, &io)) != 0) {
            log_wrn("read io failed %d", ret);
            goto err;
        }

        log_dbg("touch level %d beep %d io %#x", io & (1 << APP_TOUCH_GPIO), beep, io);

        plat_delay_ms(100);
    }

err:
    exit_handler(0);
    return 0;
}

/* End of file */
